
<template>
  <div v-show="showMenu" class="map-contextmenu" :style="styleObject" @click.stop="" @mousedown.stop="">
    <template v-for="(item, index) in menuItems">
      <div v-if="item=='-'" :key="index" class="map-contextmenu-divider"></div>
      <div
        v-if="item!='-'"
        :key="index"
        @click="_menuclick(item,index)"
        class="map-contextmenu-item"
      >{{item}}</div>
    </template>
  </div>
</template>

<script>
export default {
  name: 'MapContextmenu',
  props: {
    // 菜单数据
    menuItems: {
      type: Array,
      default: function () {
        return []
      }
    },
    // 菜单的宽度
    menuWidth: {
      type: String,
      default: 'auto'
    }
  },
  data () {
    return {
      showMenu: false,
      // 菜单大小是否发生变化
      menuSizeChanged: false,
      // 缓存menuSize
      menuSize: null,
      // 点击右键时的event
      event: null,
      styleObject: {
        width: this.menuWidth,
        left: '0px',
        top: '0px',
        right: 'auto',
        bottom: 'auto'
      }
    }
  },
  mounted () {
    var parent = this.$parent.mapObject
    parent.on(
      {
        // 右键点击事件
        contextmenu: this.showContextmenu,
        // 左键点击、鼠标按下、缩放地图事件
        click: this.hideContextmenu,
        mousedown: this.hideContextmenu,
        zoomstart: this.hideContextmenu
      },
      this
    )
  },
  watch: {
    // 如果 `menuItems` 发生改变，这个函数就会运行
    menuItems: function (newMenuItems, oldMenuItems) {
      this.menuSizeChanged = true
      console.log('menuItems changed')
    }
  },
  methods: {
    // 显示菜单
    showContextmenu (e) {
      // 记录此event
      this.event = e
      // 鼠标位置
      var point = e.containerPoint

      // 父元素的宽高
      var parentSize = {
        width: this.$parent.$el.offsetWidth,
        height: this.$parent.$el.offsetHeight
      }
      // 菜单的宽高
      this._calculateMenuSize()

      // 计算右侧是否能完全显示菜单
      if (point.x + this.menuSize.width > parentSize.width) {
        this.styleObject.left = 'auto'
        this.styleObject.right =
          Math.min(
            Math.max(parentSize.width - point.x, 0),
            parentSize.width - this.menuSize.width - 1
          ) + 'px'
      } else {
        this.styleObject.left = Math.max(point.x, 0) + 'px'
        this.styleObject.right = 'auto'
      }

      // 计算下侧是否能完全显示菜单
      if (point.y + this.menuSize.height > parentSize.height) {
        this.styleObject.top = 'auto'
        this.styleObject.bottom =
          Math.min(
            Math.max(parentSize.height - point.y, 0),
            parentSize.height - this.menuSize.height - 1
          ) + 'px'
      } else {
        this.styleObject.top = Math.max(point.y, 0) + 'px'
        this.styleObject.bottom = 'auto'
      }

      this.showMenu = true
    },
    // 隐藏菜单
    hideContextmenu () {
      if (!this.showMenu) {
        return
      }
      this.showMenu = false
    },
    // 计算menu大小
    _calculateMenuSize () {
      var el = this.$el
      var initialDisplay = el.style.display

      if (!this.menuSize || this.menuSizeChanged) {
        this.menuSize = {}

        el.style.left = '-999999px'
        el.style.right = 'auto'
        el.style.display = 'block'

        this.menuSize.width = el.offsetWidth
        this.menuSize.height = el.offsetHeight

        el.style.left = 'auto'
        el.style.display = initialDisplay

        this.menuSizeChanged = false
      }
    },
    _menuclick (item, index) {
      this.hideContextmenu()
      this.$emit('click', this.event, item, index)
    }
  }
}
</script>

<style>
.map-contextmenu {
  position: absolute;
  background-color: #fff;
  box-shadow: 0 1px 7px rgba(0, 0, 0, 0.4);
  -webkit-border-radius: 4px;
  border-radius: 4px;
  padding: 4px 0;
  user-select: none;
  z-index: 999999;
  cursor: default;
}
.map-contextmenu .map-contextmenu-divider {
  border-bottom: 1px solid #ccc;
  margin: 5px 0;
}
.map-contextmenu .map-contextmenu-item {
  display: block;
  color: #222;
  font-size: 12px;
  line-height: 20px;
  text-decoration: none;
  padding: 0 12px;
  border-top: 1px solid transparent;
  border-bottom: 1px solid transparent;
  outline: none;
}

.map-contextmenu .map-contextmenu-item:hover {
  background-color: #f4f4f4;
  border-top: 1px solid #f0f0f0;
  border-bottom: 1px solid #f0f0f0;
}
</style>
